package logic

import (
	"baokaobang/models"
	"baokaobang/utils"
	"fmt"
	"github.com/go-xorm/xorm"
	"math"
	"math/rand"
	"strings"
	"time"
)

// 根据学生成绩给学生匹配院校
func MatchCollege(sess *xorm.Session, studentId int64, score int) map[string]interface{} {
	siteConfig := new(models.SiteConfig)
	_, err := sess.ID(1).Get(siteConfig)
	if err != nil {
		return utils.CommonRes(1000, fmt.Sprintf("网站配置信息查询出错：%s", err.Error()), "")
	}

	student := new(models.User)
	_, err = sess.ID(studentId).Get(student)
	if err != nil {
		return utils.CommonRes(1000, fmt.Sprintf("学生信息查询出错：%s", err.Error()), "")
	}

	year := utils.Atoi(time.Now().Format("2006"))

	rank := new(models.Rank)
	if siteConfig.IsTest == 1 { // 高考结束，按今年的排名
		ok, _ := sess.Where("`year` = ? and `subject` = ? and `score` = ?", year, student.Subject, score).Get(rank)
		if !ok {
			return utils.CommonRes(1000, fmt.Sprintf("%s 未匹配到今年位次", student.Name), "")
		}
	} else { // 未开始高考，按去年的排名
		ok, _ := sess.Where("`year` = ? and `subject` = ? and `score` = ?", year-1, student.Subject, score).Get(rank)
		if !ok {
			return utils.CommonRes(1000, fmt.Sprintf("%s 未匹配到去年位次", student.Name), "")
		}
	}
	rankArr := strings.Split(rank.Section, "~")

	studentUpdateData := map[string]interface{}{
		"rank_num": rankArr[1],
	}
	if siteConfig.IsTest == 1 {
		studentUpdateData["test_score"] = score
	} else {
		studentUpdateData["simulate_score"] = score
	}

	// 全国可以上的大学百分比
	totalCollegeCount, err := sess.Table(new(models.CollegeEnrollment)).Where("`year` = ?", year-1).Count()
	if err != nil {
		return utils.CommonRes(1000, fmt.Sprintf("查询全国大学出错：%s", err.Error()), "")
	}
	enrollCollegeCount, err := sess.Table(new(models.CollegeEnrollment)).Where("`year` = ? and `subject` = ? and `min_score_rank` >= ?", year-1, student.Subject, rankArr[1]).Count()
	if err != nil {
		return utils.CommonRes(1000, fmt.Sprintf("查询全国可以上的大学出错：%s", err.Error()), "")
	}
	percent := math.Floor((float64(enrollCollegeCount) / float64(totalCollegeCount)) * 100)
	studentUpdateData["percent"] = percent

	enrollCollegeList := make([]models.CollegeEnrollmentObj, 0)
	err = sess.Table(new(models.CollegeEnrollment)).Alias("ce").
		Join("INNER", []string{"college", "c"}, "ce.college_id = c.id").
		Where("ce.year = ? and ce.subject = ? and ce.min_score_rank >= ?", year-1, student.Subject, rankArr[1]).Limit(1).Find(&enrollCollegeList)
	if err != nil {
		return utils.CommonRes(1000, fmt.Sprintf("查询可以上的大学出错：%s", err.Error()), "")
	}
	studentUpdateData["enroll_college_name"] = enrollCollegeList[0].CollegeData.Name

	_, err = sess.Table(new(models.User)).ID(student.Id).Update(studentUpdateData)
	if err != nil {
		return utils.CommonRes(1000, fmt.Sprintf("%s的信息更新出错：%s", err.Error()), "")
	}

	rand.Seed(time.Now().UnixNano())

	// 开始匹配大学
	if student.IsBuyEnsureAdmission == 1 { // 学生购买了优录计划，从合作院校中进行匹配

		ok, err := sess.Table(new(models.MatchTeacher)).Where("student_id = ? and match_type = 1", student.Id).Exist()
		if err != nil {
			return utils.CommonRes(1000, fmt.Sprintf("匹配辅导员出错：%s", err.Error()), "")
		}
		if !ok {
			teacherList := make([]models.User, 0)
			err = sess.Table(new(models.User)).Where("user_type = 4").Find(&teacherList)
			if err != nil {
				return utils.CommonRes(1000, fmt.Sprintf("查询所有辅导员出错：%s", err.Error()), "")
			}
			if len(teacherList) <= 0 {
				return utils.CommonRes(1000, "没有匹配到任何辅导员", "")
			}

			rand.Seed(time.Now().UnixNano())
			teacherLen := len(teacherList) - 1
			matchTeacher := new(models.MatchTeacher)
			matchTeacher.MatchType = 1
			matchTeacher.StudentId = student.Id
			matchTeacher.TeacherId = teacherList[rand.Intn(teacherLen)].Id
			_, err = sess.InsertOne(matchTeacher)
			if err != nil {
				return utils.CommonRes(1000, fmt.Sprintf("辅导员匹配出错：%s", err.Error()), "")
			}
		}

		collegeEnrollmentListOne := make([]models.CollegeEnrollmentObj, 0)
		err = sess.Table(new(models.CollegeEnrollment)).Alias("ce").
			Join("INNER", []string{"college", "c"}, "ce.college_id = c.id").
			Where("c.is_cooperation = 1 and ce.year = ? and ce.subject = ? and ce.min_score_rank >= ?", year-1, student.Subject, rankArr[1]).
			Asc("ce.batch").Limit(1, 0).Find(&collegeEnrollmentListOne)
		if err != nil {
			return utils.CommonRes(1000, fmt.Sprintf("匹配院校出错：%s", err.Error()), "")
		}
		if len(collegeEnrollmentListOne) <= 0 {
			return utils.CommonRes(1000, fmt.Sprintf("%s 未匹配到任何院校", student.Name), "")
		}

		var list []string

		// 本科一批院校（通过distinct去重了）
		sqlOne := fmt.Sprintf("select distinct ce.college_id from college_enrollment ce inner join college c on ce.college_id = c.id where c.is_cooperation = 1 and ce.year = %d and ce.subject = %d and ce.min_score_rank >= %s and ce.batch = 1", year-1, student.Subject, rankArr[1])
		oneList, err := sess.QueryString(sqlOne)
		if err != nil {
			return utils.CommonRes(1000, fmt.Sprintf("匹配院校出错：%s", err.Error()), "")
		}

		// 本科二批院校（通过distinct去重了）
		sqlTwo := fmt.Sprintf("select distinct ce.college_id from college_enrollment ce inner join college c on ce.college_id = c.id where c.is_cooperation = 1 and ce.year = %d and ce.subject = %d and ce.min_score_rank >= %s and ce.batch = 2", year-1, student.Subject, rankArr[1])
		twoList, err := sess.QueryString(sqlTwo)
		if err != nil {
			return utils.CommonRes(1000, fmt.Sprintf("匹配院校出错：%s", err.Error()), "")
		}

		// 高职高专批院校（通过distinct去重了）
		sqlThree := fmt.Sprintf("select distinct ce.college_id from college_enrollment ce inner join college c on ce.college_id = c.id where c.is_cooperation = 1 and ce.year = %d and ce.subject = %d and ce.min_score_rank >= %s and ce.batch = 3", year-1, student.Subject, rankArr[1])
		threeList, err := sess.QueryString(sqlThree)
		if err != nil {
			return utils.CommonRes(1000, fmt.Sprintf("匹配院校出错：%s", err.Error()), "")
		}

		if collegeEnrollmentListOne[0].CollegeEnrollment.Batch == 1 { // 若匹配到本科一批院校，则不需要匹配高职高专批院校
			if len(oneList) > 7 {
				oneLen := len(oneList) - 1
				for i := 0; i < 7; i++ {
					if i > oneLen {
						break
					}
					a := rand.Intn(oneLen)
					collegeIdA := oneList[a]["college_id"]
					if len(list) > 0 {
						collegeIdB := list[len(list)-1]
						for collegeIdA == collegeIdB {
							a = rand.Intn(oneLen)
							collegeIdA = oneList[a]["college_id"]
						}
					}
					list = append(list, collegeIdA)
				}
			} else {
				if len(oneList) > 0 {
					for i := 0; i < len(oneList); i++ {
						list = append(list, oneList[i]["college_id"])
					}
				}
			}

			if len(twoList) > 7 {
				twoLen := len(twoList) - 1
				for i := 0; i < 7; i++ {
					if i > twoLen {
						break
					}
					a := rand.Intn(twoLen)
					collegeIdA := twoList[a]["college_id"]
					if len(list) > 0 {
						collegeIdB := list[len(list)-1]
						for collegeIdA == collegeIdB {
							a = rand.Intn(twoLen)
							collegeIdA = twoList[a]["college_id"]
						}
					}
					list = append(list, collegeIdA)
				}
			} else {
				if len(twoList) > 0 {
					for i := 0; i < len(twoList); i++ {
						list = append(list, twoList[i]["college_id"])
					}
				}
			}
		} else {
			if len(twoList) > 7 {
				twoLen := len(twoList) - 1
				for i := 0; i < 7; i++ {
					if i > twoLen {
						break
					}
					a := rand.Intn(twoLen)
					collegeIdA := twoList[a]["college_id"]
					if len(list) > 0 {
						collegeIdB := list[len(list)-1]
						for collegeIdA == collegeIdB {
							a = rand.Intn(twoLen)
							collegeIdA = twoList[a]["college_id"]
						}
					}
					list = append(list, collegeIdA)
				}
			} else {
				if len(twoList) > 0 {
					for i := 0; i < len(twoList); i++ {
						list = append(list, twoList[i]["college_id"])
					}
				}
			}

			if len(threeList) > 10 {
				threeLen := len(threeList) - 1
				for i := 0; i < 10; i++ {
					if i > threeLen {
						break
					}
					a := rand.Intn(threeLen)
					collegeIdA := threeList[a]["college_id"]
					if len(list) > 0 {
						collegeIdB := list[len(list)-1]
						for collegeIdA == collegeIdB {
							a = rand.Intn(threeLen)
							collegeIdA = threeList[a]["college_id"]
						}
					}
					list = append(list, collegeIdA)
				}
			} else {
				if len(threeList) > 0 {
					for i := 0; i < len(threeList); i++ {
						list = append(list, threeList[i]["college_id"])
					}
				}
			}
		}

		for _, collegeId := range list {
			matchCollege := new(models.MatchCollege)
			matchCollege.UserId = student.Id
			matchCollege.CollegeId = utils.Atoi64(collegeId)
			matchCollege.MatchType = 1
			matchCollege.IsBuyEnsureAdmission = 1
			matchCollege.Year = year
			matchCollege.IsTest = siteConfig.IsTest
			matchCollege.Score = score
			_, err = sess.InsertOne(matchCollege)
			if err != nil {
				return utils.CommonRes(1000, fmt.Sprintf("插入匹配院校出错：%s", err.Error()), "")
			}
		}

	} else if student.IsBuySingleAction == 1 { // 学生购买了单招模式，从单招院校中进行匹配

		ok, err := sess.Table(new(models.MatchTeacher)).Where("student_id = ? and match_type = 1", student.Id).Exist()
		if err != nil {
			return utils.CommonRes(1000, fmt.Sprintf("匹配单招辅导员出错：%s", err.Error()), "")
		}
		if !ok {
			teacherList := make([]models.User, 0)
			err = sess.Table(new(models.User)).Where("user_type = 4").Find(&teacherList)
			if err != nil {
				return utils.CommonRes(1000, fmt.Sprintf("查询所有辅导员出错：%s", err.Error()), "")
			}
			if len(teacherList) <= 0 {
				return utils.CommonRes(1000, "没有匹配到任何辅导员", "")
			}

			teacherLen := len(teacherList) - 1
			matchTeacher := new(models.MatchTeacher)
			matchTeacher.MatchType = 1
			matchTeacher.StudentId = student.Id
			matchTeacher.TeacherId = teacherList[rand.Intn(teacherLen)].Id
			_, err = sess.InsertOne(matchTeacher)
			if err != nil {
				return utils.CommonRes(1000, fmt.Sprintf("辅导员匹配出错：%s", err.Error()), "")
			}
		}

		collegeList := make([]models.College, 0)
		err = sess.Where("is_single = 1 and single_score <= ?", score).Find(&collegeList)
		if err != nil {
			return utils.CommonRes(1000, fmt.Sprintf("匹配单招院校出错：%s", err.Error()), "")
		}
		if len(collegeList) <= 0 {
			return utils.CommonRes(1000, "未匹配到任何单招院校", "")
		}

		var collegeIds []int64
		if len(collegeList) > 3 {
			collegeLen := len(collegeList) - 1
			for i := 0; i < 3; i++ {
				if i > collegeLen {
					break
				}
				a := rand.Intn(collegeLen)
				collegeIdA := collegeList[a].Id
				if len(collegeIds) > 0 {
					collegeIdB := collegeIds[len(collegeIds)-1]
					for collegeIdA == collegeIdB {
						a = rand.Intn(collegeLen)
						collegeIdA = collegeList[a].Id
					}
				}
				matchCollege := new(models.MatchCollege)
				matchCollege.UserId = student.Id
				matchCollege.CollegeId = collegeIdA
				matchCollege.MatchType = 2
				matchCollege.IsBuyEnsureAdmission = 0
				matchCollege.Year = year
				matchCollege.IsTest = siteConfig.IsTest
				matchCollege.Score = score
				_, err = sess.InsertOne(matchCollege)
				if err != nil {
					return utils.CommonRes(1000, fmt.Sprintf("插入匹配院校出错：%s", err.Error()), "")
				}
			}
		} else {
			if len(collegeList) > 0 {
				for i := 0; i < 3; i++ {
					matchCollege := new(models.MatchCollege)
					matchCollege.UserId = student.Id
					matchCollege.CollegeId = collegeList[i].Id
					matchCollege.MatchType = 2
					matchCollege.IsBuyEnsureAdmission = 0
					matchCollege.Year = year
					matchCollege.IsTest = siteConfig.IsTest
					matchCollege.Score = score
					_, err = sess.InsertOne(matchCollege)
					if err != nil {
						return utils.CommonRes(1000, fmt.Sprintf("插入匹配院校出错：%s", err.Error()), "")
					}
				}
			}
		}
	} else { // 学生什么都没购买，从全省院校中进行匹配

		collegeEnrollmentListOne := make([]models.CollegeEnrollmentObj, 0)
		err = sess.Table(new(models.CollegeEnrollment)).Alias("ce").
			Join("INNER", []string{"college", "c"}, "ce.college_id = c.id").
			Join("INNER", []string{"university", "u"}, "c.university_id = u.id").
			Where("u.province_id = 16 and ce.year = ? and ce.subject = ? and ce.min_score_rank >= ?", year-1, student.Subject, rankArr[1]).
			Asc("ce.batch").Limit(1, 0).Find(&collegeEnrollmentListOne)
		if err != nil {
			return utils.CommonRes(1000, fmt.Sprintf("匹配院校出错：%s", err.Error()), "")
		}
		if len(collegeEnrollmentListOne) <= 0 {
			return utils.CommonRes(1000, fmt.Sprintf("%s 未匹配到任何院校", student.Name), "")
		}

		var list []string

		// 本科一批院校（通过distinct去重了）
		sqlOne := fmt.Sprintf("select distinct ce.college_id from college_enrollment ce inner join college c on ce.college_id = c.id inner join university u on c.university_id = u.id where u.province_id = 16 and ce.year = %d and ce.subject = %d and ce.min_score_rank >= %s and ce.batch = 1", year-1, student.Subject, rankArr[1])
		oneList, err := sess.QueryString(sqlOne)
		if err != nil {
			return utils.CommonRes(1000, fmt.Sprintf("匹配院校出错：%s", err.Error()), "")
		}

		// 本科二批院校（通过distinct去重了）
		sqlTwo := fmt.Sprintf("select distinct ce.college_id from college_enrollment ce inner join college c on ce.college_id = c.id inner join university u on c.university_id = u.id where u.province_id = 16 and ce.year = %d and ce.subject = %d and ce.min_score_rank >= %s and ce.batch = 2", year-1, student.Subject, rankArr[1])
		twoList, err := sess.QueryString(sqlTwo)
		if err != nil {
			return utils.CommonRes(1000, fmt.Sprintf("匹配院校出错：%s", err.Error()), "")
		}

		// 高职高专批院校（通过distinct去重了）
		sqlThree := fmt.Sprintf("select distinct ce.college_id from college_enrollment ce inner join college c on ce.college_id = c.id inner join university u on c.university_id = u.id where u.province_id = 16 and ce.year = %d and ce.subject = %d and ce.min_score_rank >= %s and ce.batch = 3", year-1, student.Subject, rankArr[1])
		threeList, err := sess.QueryString(sqlThree)
		if err != nil {
			return utils.CommonRes(1000, fmt.Sprintf("匹配院校出错：%s", err.Error()), "")
		}

		if collegeEnrollmentListOne[0].CollegeEnrollment.Batch == 1 {
			if len(oneList) > 12 {
				oneLen := len(oneList) - 1
				for i := 0; i < 12; i++ {
					if i > oneLen {
						break
					}
					a := rand.Intn(oneLen)
					collegeIdA := oneList[a]["college_id"]
					if len(list) > 0 {
						collegeIdB := list[len(list)-1]
						for collegeIdA == collegeIdB {
							a = rand.Intn(oneLen)
							collegeIdA = oneList[a]["college_id"]
						}
					}
					list = append(list, collegeIdA)
				}
			} else {
				if len(oneList) > 0 {
					for i := 0; i < len(oneList); i++ {
						list = append(list, oneList[i]["college_id"])
					}
				}
			}

			if len(twoList) > 12 {
				twoLen := len(twoList) - 1
				for i := 0; i < 12; i++ {
					if i > twoLen {
						break
					}
					a := rand.Intn(twoLen)
					collegeIdA := twoList[a]["college_id"]
					if len(list) > 0 {
						collegeIdB := list[len(list)-1]
						for collegeIdA == collegeIdB {
							a = rand.Intn(twoLen)
							collegeIdA = twoList[a]["college_id"]
						}
					}
					list = append(list, collegeIdA)
				}
			} else {
				if len(twoList) > 0 {
					for i := 0; i < len(twoList); i++ {
						list = append(list, twoList[i]["college_id"])
					}
				}
			}
		} else {
			if len(twoList) > 12 {
				twoLen := len(twoList) - 1
				for i := 0; i < 12; i++ {
					if i > twoLen {
						break
					}
					a := rand.Intn(twoLen)
					collegeIdA := twoList[a]["college_id"]
					if len(list) > 0 {
						collegeIdB := list[len(list)-1]
						for collegeIdA == collegeIdB {
							a = rand.Intn(twoLen)
							collegeIdA = twoList[a]["college_id"]
						}
					}
					list = append(list, collegeIdA)
				}
			} else {
				if len(twoList) > 0 {
					for i := 0; i < len(twoList); i++ {
						list = append(list, twoList[i]["college_id"])
					}
				}
			}

			if len(threeList) > 18 {
				threeLen := len(threeList) - 1
				for i := 0; i < 18; i++ {
					if i > threeLen {
						break
					}
					a := rand.Intn(threeLen)
					collegeIdA := threeList[a]["college_id"]
					if len(list) > 0 {
						collegeIdB := list[len(list)-1]
						for collegeIdA == collegeIdB {
							a = rand.Intn(threeLen)
							collegeIdA = threeList[a]["college_id"]
						}
					}
					list = append(list, collegeIdA)
				}
			} else {
				if len(threeList) > 0 {
					for i := 0; i < len(threeList); i++ {
						list = append(list, threeList[i]["college_id"])
					}
				}
			}
		}

		var probability float64

		for _, collegeId := range list {
			matchCollege := new(models.MatchCollege)
			matchCollege.UserId = student.Id
			matchCollege.CollegeId = utils.Atoi64(collegeId)
			matchCollege.MatchType = 1
			matchCollege.IsBuyEnsureAdmission = 0
			matchCollege.Year = year
			matchCollege.IsTest = siteConfig.IsTest
			matchCollege.Score = score
			_, err = sess.InsertOne(matchCollege)
			if err != nil {
				return utils.CommonRes(1000, fmt.Sprintf("插入匹配院校出错：%s", err.Error()), "")
			}

			// 计算学生专业录取概率
			enrollmentPlanList := make([]models.EnrollmentPlan, 0)
			err = sess.Where("`college_id` = ? and `year` = ? and `m_type` = ?", collegeId, year, student.Subject).Find(&enrollmentPlanList)
			if err != nil {
				return utils.CommonRes(1000, fmt.Sprintf("查询院校招生计划出错：%s", err.Error()), "")
			}
			for _, enrollmentPlan := range enrollmentPlanList {
				probability = 0
				totalCount, err := sess.Table(new(models.AdmissionData)).
					Where("`college_id` = ? and `subject` = ? and `major_name` like ?", collegeId, student.Subject, fmt.Sprintf("%%%s%%", strings.TrimSpace(enrollmentPlan.MajorName))).
					Count()
				if err != nil {
					return utils.CommonRes(1000, fmt.Sprintf("计算专业录取概率出错：%s", err.Error()), "")
				}
				if totalCount > 0 {
					probability = utils.Atof64(fmt.Sprintf("%.2f", rand.Float64()))
					matchCount, err := sess.Table(new(models.AdmissionData)).
						Where("`college_id` = ? and `subject` = ? and `min_score_high` >= ? and `major_name` like ?", collegeId, student.Subject, rankArr[1], fmt.Sprintf("%%%s%%", strings.TrimSpace(enrollmentPlan.MajorName))).
						Count()
					if err != nil {
						return utils.CommonRes(1000, fmt.Sprintf("计算专业录取概率出错：%s", err.Error()), "")
					}
					probability = utils.Atof64(fmt.Sprintf("%.2f", float64(matchCount)/float64(totalCount)))*100 + probability
				}
				if probability >= 100 {
					probability = 99.99
				}

				studentMajorProbability := new(models.StudentMajorProbability)
				studentMajorProbability.UserId = student.Id
				studentMajorProbability.CollegeId = utils.Atoi64(collegeId)
				studentMajorProbability.EnrollmentPlanId = enrollmentPlan.Id
				studentMajorProbability.Year = year
				studentMajorProbability.Probability = probability
				_, err = sess.InsertOne(studentMajorProbability)
				if err != nil {
					return utils.CommonRes(1000, fmt.Sprintf("插入专业录取概率出错：%s", err.Error()), "")
				}
			}
		}

	}

	sess.Commit()

	return utils.CommonRes(20000, "操作成功", "")
}

// 获取用户额外信息
func GetUserExtraInfo(db *xorm.Engine, user *models.User) map[string]interface{} {
	year := utils.Atoi(time.Now().Format("2006"))
	user.PhoneShow = utils.FormatMobile(user.Phone)

	if user.IsExpert == 1 {
		user.UserTypeShow = "专家"
	} else {
		user.UserTypeShow = models.UserType[user.UserType]
	}

	if user.UserType == 1 { // 学生
		siteConfig := new(models.SiteConfig)
		ok, _ := db.ID(1).Get(siteConfig)
		if !ok {
			return utils.CommonRes(1000, "无法获取配置信息", "")
		}
		user.IsExamination = siteConfig.IsTest

		ok, err := db.Table(new(models.Volunteer)).Where("user_id = ? and year = ?", user.Id, year).Exist()
		if err != nil {
			return utils.CommonRes(1000, fmt.Sprintf("查询用户志愿模拟结果出错：%s", err.Error()), "")
		}
		if ok {
			user.IsVolunteerTest = 1
		} else {
			user.IsVolunteerTest = 0
		}
	}

	college := new(models.College)
	if user.UserType == 2 || user.UserType == 3 {
		ok, err := db.ID(user.CollegeId).Get(college)
		if err != nil {
			return utils.CommonRes(1000, fmt.Sprintf("根据用户学院id查询出错：%s", err.Error()), "")
		}
		if !ok {
			return utils.CommonRes(1000, "用户学院信息不存在", "")
		}
		user.CollegeCode = college.Code
		user.CollegeName = college.Name
	}

	user.Albums = strings.Split(user.AlbumList, ",")

	userLabelCount, _ := db.Table(new(models.UserLabel)).Where("`user_id` = ?", user.Id).Count()
	if userLabelCount > 0 {
		user.IsSelectedLabel = 1
	}

	return utils.CommonRes(20000, "操作成功", "")
}
